﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Speech.Synthesis;

// Bing Maps Namespace
using Microsoft.Maps.MapControl;
using Microsoft.Maps.MapControl.WPF;

// KSA specific
using KSATouch;
using KSAWPFExtensions;

namespace KSAWPFDemo
{
    /// <summary>
    /// Interaction logic for MapControl.xaml
    /// </summary>
    public partial class MapControl : UserControl
    {
        private KSAWPFExtensions.KSAWPFWindow mainWindow;
        //private SpeechSynthesizer synth = new SpeechSynthesizer();
        private DateTime LastChange; // track when the last height change occurred
        const int DelayTimeToZoom = 0;
        string[] commands = new string[] { "Aerial", "Road", "Clink", "Colluseum" , "Center", "about"};
        // track one contact 'from the side' for hover
        int trackedID = -1;

        public MapControl()
        {
            InitializeComponent();
            this.Loaded += MapControl_Loaded;
        }

        void MapControl_Loaded(object sender, RoutedEventArgs e)
        {
            // Note: This must always be called from the loaded event, otherwise it'll return null
            KSAWPFWindow mainWindow = KSAWPFWindow.GetWindow(this) as KSAWPFWindow;
            if (mainWindow != null)
            {
                mainWindow.FrameReady += mainWindow_FrameReady;
                mainWindow.KeyDown += mainWindow_KeyDown;
                //synth.SelectVoice("Microsoft Hazel Desktop");

                try
                {
                    mainWindow.KsaTouch.AddVoiceCommand(commands);

                }
                catch (Exception exc)
                {
                    // kinect most likely not initialized...do not worry about enabling voice
                    System.Diagnostics.Debug.WriteLine("Kinect sensor is not initialized! " + exc.Message);
                }
                
                mainWindow.VoiceCommandRecognized += mainWindow_VoiceCommandRecognized;
                
            }

            LastChange = DateTime.Now;
            BingMap.Mode = new AerialMode(true);
            BingMap.AnimationLevel = AnimationLevel.Full; // may stress procs
            BingMap.ViewChangeStart += BingMap_ViewChangeStart;

  
        }

        void mainWindow_VoiceCommandRecognized(string command)
        {
            this.Dispatcher.BeginInvoke(new Action(delegate()
            {
                HandleVoiceCommands(command);
            }));

        }
        void HandleVoiceCommands(string command)
        {
            switch (command.ToLower())
            {
                case "aerial":
                    {
                        BingMap.Mode = new AerialMode();
                        //synth.Speak("Aerial Mode");
                        break;
                    }
                case "road":
                    {
                        BingMap.Mode = new RoadMode();
                        //synth.SpeakAsync("Displaying Roads");
                        break;
                    }
                case "clink":
                    { 
                        // Seattle Seahawks stadium
                        BingMap.SetView(new Location(47.59501083000102, -122.33158886957427), 18);
                        //synth.SpeakAsync("Navigating to Century link stadium");
                        break;
                    }
                case "colluseum":
                    { 
                        // Colluseum in Rome
                        BingMap.SetView(new Location(41.89033, 12.49264), 20);
                        //synth.SpeakAsync("Navigating to the Roman Colluseum");
                        break;
                    }
                case "center":
                    {
                        // Colluseum in Rome
                        BingMap.SetView(new Location(47.6221666, -122.35022), 18);
                        break;
                    }
                case "about":
                    {
                        // MAKER: This may be a bad idea
                        //synth.SpeakAsync("Construction began under the emperor Vespasian in 70 AD, and was completed in 80 AD under his successor and heir Titus");
                        break;
                    }
            }
        }

        void BingMap_ViewChangeStart(object sender, MapEventArgs e)
        {
            location.Content = BingMap.Center.ToString() + "Zoom: " + BingMap.ZoomLevel;
        }

        void mainWindow_KeyDown(object sender, KeyEventArgs e)
        {
           
            // for debugging keystrokes
            if (e.Key == Key.Z)
            {
                BingMap.SetView(new Location(41.89033, 12.49264), 20);
            }
            if (e.Key == Key.D)
            {
                BingMap.SetView(new Location(47.6221666,-122.35022), 18);
            }
            if (e.Key == Key.S)
            {
                BingMap.Mode = new RoadMode();
            }
            if (e.Key == Key.F)
            {
                BingMap.Mode = new AerialMode();
            }
           
            if (e.Key == Key.A)
            {
                BingMap.SetView(new Location(47.59501083000102, -122.33158886957427), 18);
            }
        }



        void mainWindow_FrameReady(object Sender, FrameReadyEventArgs e)
        {
            
            if ((e.HoveringContacts.Count > 0) && (e.CurrentContacts.Count == 0))
            {
                if (trackedID == -1)
                {
                    foreach (Contact contact in e.HoveringContacts)
                    { 
                        if((contact.CenterPoint.X < 120) && (contact.ContactZHeight > 1))
                        {
                            // contact detected 'in range'...assign its id
                            trackedID = contact.Id;
                            HeightSlider.Visibility = Visibility.Visible;
                        }
                    }
                }
                else
                {                  
                    // only change once every few seconds
                    if (DateTime.Now.Subtract(LastChange) < TimeSpan.FromMilliseconds(DelayTimeToZoom))
                    {
                        return;
                    }
                    Contact hoverContact = e.HoveringContacts.Where(con => con.Id == trackedID).FirstOrDefault();
                    if (hoverContact == null)
                    {
                        trackedID = -1;
                        LastChange = DateTime.Now;
                        HeightSlider.Visibility = System.Windows.Visibility.Hidden;
                        return;
                    }
                    int height = hoverContact.ContactZHeight;
                    if ((hoverContact.CenterPoint.X < 420) && (height > 1))
                    {
                        HeightSlider.Visibility = System.Windows.Visibility.Visible;
                        if (height > 0)
                        {
                            HeightSlider.Value = height;
                            statusLabel.Content = "Hover Detected at: " + height;
                            if (height < 180)
                            {
                                ZoomDown();
                                LastChange = DateTime.Now;
                            }
                            if (height > 260)
                            {
                                ZoomUp();
                                LastChange = DateTime.Now;
                            }
                        }
                    }
                    else
                    { 
                        // contacts 'out of range'
                        trackedID = -1;
                        HeightSlider.Visibility = Visibility.Hidden;
                    }

                } // end else (trackedid != -1
            }
        }

        private void ZoomDown()
        {
            BingMap.ZoomLevel += .1;
        }
        private void ZoomUp()
        {
            BingMap.ZoomLevel -= .1;
        }

    }
}
